from flask import Flask, render_template, request, redirect, url_for, session, jsonify
from datetime import datetime
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField, PasswordField, FileField
from wtforms.validators import DataRequired, Length
from flask_sqlalchemy import SQLAlchemy
from flask_paginate import Pagination, get_page_parameter
from flask_migrate import Migrate
from werkzeug.utils import secure_filename
import os, string, random

base_dir = os.path.abspath(os.path.dirname(__file__)) # 获取文件所在的文件夹完整路径
app = Flask(__name__, static_url_path="/")            # 创建flask对象实例，其中static_url_path为static文件夹所在位置
app.config['SECRET_KEY'] = 'asdf8*sdfkcv'             # 设置表单密匙,方便在提交表单时加密
app.config['SQLALCHEMY_DATABASE_URI'] = \
    'sqlite:///' + os.path.join(base_dir, 'data.sqlite') # 设置数据库data.sqlite的位置
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # 提升数据库的性能
db = SQLAlchemy(app)                                # 创建数据库实例对象
migrate = Migrate(app, db)                          # 创建数据库迁移对象
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'JPG', 'PNG', 'bmp']) # 创建获批准的图片格式集合

def allowed_file(filename):
    '''判断文件格式是否符合标准是则返回True不是则返回False'''
    return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

class AdminForm(FlaskForm):
    '''发动态所需要的表单类'''
    img = FileField('图片:')
    text  = TextAreaField('正文:', validators=[DataRequired(), Length(max=300)])
    submit= SubmitField  ('提交')

class LoginForm(FlaskForm):
    '''登陆所需要的表单类'''
    name = StringField('用户名:', validators=[DataRequired(), Length(max=15)])
    password = PasswordField('密码:', validators=[DataRequired(), Length(max=15)])
    submit = SubmitField('登陆')

class User(db.Model):
    '''存储用户数据的数据库类'''
    id    = db.Column(db.Integer, primary_key=True)
    name  = db.Column(db.String(30))
    password  = db.Column(db.String(30))

class Text(db.Model):
    '''按一个条目为单位存储数据的数据库类'''
    id    = db.Column(db.Integer, primary_key=True)
    text  = db.Column(db.String(300))
    date  = db.Column(db.String(30))
    imgP  = db.Column(db.String(200), unique=True)

    def __repr__(self):
        return 'Text<title:%r>' % self.text[:10] + "..."

@app.route("/")
def index():
    '''首页'''
    flag = session.get('know', False)
    search = False
    q = request.args.get('q')
    if q:
        search = True
    limit = 5 # 设置每页显示的页数
    text = Text.query.order_by('id') # 获取数据库对象Text的数据列表
    page = request.args.get(get_page_parameter(), type=int, default=1) 
    start = (page - 1) * limit
    end = page * limit if text.count() > page * limit else text.count()
    ret = text.slice(start, end)
    pagination = Pagination(page=page, total=text.count(), bs_version=4, search=search, per_page=limit) # 创建分页对象, page是当前页码, total是数据数量, bs_version是bootstrap版本, search是是否开启搜索, per_page是每页显示多少条数据。
    return render_template('index.html', text=ret, pagination=pagination, flag=flag)

@app.route("/admin", methods=['GET', 'POST'])
def admin():
    '''发动态页'''
    if not session.get('know', False):
        return redirect(url_for('login'))
    if session['know']:
        if request.method == 'POST':
            form = request.form
            text  = form['text']
            imge  = request.files['img']
            img_name = None
            if imge:
                if not (imge and allowed_file(imge.filename)):
                    return "<small>请检查上传的图片类型，仅限于png、PNG、jpg、JPG、bmp</small>"
                random_str = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))
                img_name = random_str+imge.filename[-4:]
                upload_path = os.path.join(base_dir, 'static\\img', secure_filename(img_name))
                imge.save(upload_path)
            date  = datetime.now().strftime("%Y.%m.%d %H:%M:%S")
            t = Text(text=text, date=date, imgP=img_name)
            db.session.add(t)
            db.session.commit()
            return redirect(url_for('index'))
        else:
            form = AdminForm()
            return render_template('admin.html', form=form)
    else:
        return redirect(url_for('login'))


@app.route("/login", methods=['GET', 'POST'])
def login():
    '''登陆页'''
    if session.get('know', False):
        return redirect(url_for('index'))
    error_message = None
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(name=form.name.data, password=form.password.data).first()
        if user:
            session['know'] = True
            return redirect(url_for('index'))
        else:
            session['know'] = False
            error_message = "登陆失败"
    return render_template('login.html', form=form, error_message=error_message)

@app.route("/command/<command>")
def execute(command):
    '''执行自定义命令页'''
    if session.get('know', False):
        if command == 'logout':
                session['know'] = False
    return redirect(url_for('index'))

@app.route("/delete", methods=['POST'])
def delete():
    '''删除动态页,只接受post请求'''
    data = request.json
    id = data['id']
    print("这是对方发来的请求数据包：", data)
    if session.get('know', False):
        obj = Text.query.filter_by(id=id).first()
        if obj:
            db.session.delete(obj)
            db.session.commit()
            message = '删除成功'
        else:
            message = '没有找到该对象'
    else:
        message = '你还没有权限这样做，臭宝宝'
    return dict(message=message)

@app.route("/change_text/<id>", methods=['GET', 'POST'])
def change_text(id):
    if session.get('know', False): # 如果获得用户授权
        form = AdminForm()
        t = Text.query.filter_by(id=id).first()
        form = AdminForm(text=t.text)
        if t.imgP:# 如果文章存了照片
            img_name = t.imgP
            upload_path = os.path.join(base_dir, 'static\\img', secure_filename(img_name))
            old_path = upload_path
        else:# 如果文章没存照片
            img_name = None
            upload_path = None
            old_path = None
        if request.method == 'POST':# 如果请求方式是post
            f = request.form
            t.text = f['text']
            is_delete_img = eval(f['is_delete_img'])
            imge  = request.files['img']
            if not is_delete_img:# 如果不清空照片
                if imge: # 如果上传了图片
                    if not (imge and allowed_file(imge.filename)): # 如果不符合图片类型
                        return "<small>请检查上传的图片类型，仅限于png、PNG、jpg、JPG、bmp</small>"
                    random_str = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))
                    img_name = random_str+imge.filename[-4:]
                    upload_path = os.path.join(base_dir, 'static\\img', secure_filename(img_name))
                    if old_path != upload_path:# 如果老照片和新照片地址不同删除老照片
                        print("旧图片地址为：%s" % old_path)
                        print("新图片地址为：%s" % upload_path)
                        print("执行删除旧图片地址")
                        if old_path:# 判断老照片是否存在，存在则删除
                            os.remove(old_path)
                    imge.save(upload_path)
            else:# 如果要清空图片
                if upload_path: # 如果文章有照片则删除
                    os.remove(upload_path)
                    img_name = None
            t.imgP = img_name
            db.session.add(t)
            db.session.commit()
            return redirect(url_for('index'))
        return render_template('change.html', form=form, id=id, img_name=upload_path, is_delete_img=False)
    else: # 如果没有获得用户授权
        return redirect(url_for('login'))

@app.shell_context_processor
def m():
    '''预加载一些重要变量到flask shell中'''
    return dict(db=db, Text=Text, User=User)
